/*
 * @Author: lujing
 * @Date: 2024-06-13 09:29:14
 * @LastEditTime: 2024-06-25 11:32:54
 * @FilePath: \workspace\fy\aiDigitalPerson\dipu-xjy-meta-digital-person\src\pages\digitalHuman\Home.tsx
 */
import {
  digitalIframeUrl123,
  digitalIframeUrl124,
  digitalIframeUrl125
} from 'api/index';
import { useEffect } from 'react';
import { toast } from 'react-hot-toast';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { v4 as uuidv4 } from 'uuid';

import FullscreenIcon from '@mui/icons-material/Fullscreen';
import {
  Box,
  Button,
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
  TextField,
  Typography
} from '@mui/material';

import ChatBox from 'components/digital/ChatContainer';
import Human from 'components/digital/HumanContainer';

import BG from 'assets/bg_20250224_yyb.mp4';
import DigitalBg from 'assets/digital-bg.png';
import fullscreenIcon from 'assets/fullscreen.png';
import pauseIcon from 'assets/pause_02.png';
import zantingIcon from 'assets/zanting-active.png';

import {
  IMessage,
  fullscreenState,
  initWAKEUP_NTF,
  isLoadingFinishState,
  isRenderingState,
  loadingState,
  messagesState,
  openComfirmState,
  promtStringState,
  sessionState,
  sessionState_rizhi,
  voicingState
} from 'state/chat';
import { clientState } from 'state/client';

export default function Home() {
  const queryString = window.location.search;
  const urlParams = new URLSearchParams(queryString);
  const shuziren =
    urlParams.get('shuziren') == '123'
      ? digitalIframeUrl123
      : urlParams.get('shuziren') == '124'
      ? digitalIframeUrl124
      : digitalIframeUrl125;
  const setIsRendering = useSetRecoilState(isRenderingState);
  const setLoading = useSetRecoilState(loadingState);
  const loading = useRecoilValue(loadingState);
  const setVoicing = useSetRecoilState(voicingState);
  const session = useRecoilValue(sessionState);
  const session_rizhi = useRecoilValue(sessionState_rizhi);
  const promtString = useRecoilValue(promtStringState);
  const [messages, setMessages] = useRecoilState(messagesState);

  let currMessageId = ''; //当前正在响应的消息id;

  let [loadingFinish, setloadingFinish] = useRecoilState(isLoadingFinishState); //加载完成，确认了页面尺寸后，再加载数字人

  const handleStopRendering = () => {
    setLoading(false);
    setIsRendering(false);
    // 打断数字人讲话，等待中
    setVoicing('event_vad_end');
    // 触发数字人讲话[停止说话]
    client.setAISay('', 'task_stop', session.socket);
    // const lastIndex = messages.findLastIndex(obj => obj.parentId === null);
    // let message: IMessage
    // 如果找到符合条件的对象，则为其添加show: true属性
    // if (lastIndex !== -1) {
    //     message = messages[lastIndex]
    //     message.stopRendering = true
    //     setMessages((oldMessages) => {
    //        return [
    //             ...oldMessages.slice(0, lastIndex),
    //             message,
    //             ...oldMessages.slice(lastIndex + 1)
    //           ]
    //     })
    // }
    // session?.socket.emit('stop');
    // session?.socket.emit('stop');
  };

  const client = useRecoilValue(clientState);
  // 一些临时数据
  let dealResultStr = ''; //解析后的字符串集合
  // 监听是否收到声音
  useEffect(() => {
    if (promtString) {
      // 当两次问题提问太快的时候用来区分上一次的问题和下一次的问题，
      // 这里将这个值传入，当做新的跟对象中的原数值对比，控制调用文字输出
      const num = initWAKEUP_NTF.num;
      // 打断上一个问题
      handleStopRendering();
      // 展示一条问题
      setLoading(true);
      const message: IMessage = {
        id: uuidv4(),
        author: '访客',
        authorIsUser: true,
        content: promtString,
        createdAt: new Date().toISOString()
      };
      // session_rizhi.socket_rizhi.send(
      //   '数字人ID:' +
      //     urlParams.get('shuziren') +
      //     ' 给到数字人展示问题时间' +
      //     getCurrentDateTime() +
      //     '，内容：' +
      //     promtString
      // ); // 发送一条日志消息

      // 添加一条消息
      setMessages((m) => [...m, message]);
      getResult(promtString, num);
      setTimeout(() => {
        setIsRendering(true);
      }, 0); //原来这里是800，yyb修改为0
    }
  }, [promtString]);

  useEffect(() => {
    // 触发数字人说开场白
    setTimeout(() => {
      client.setAISay(
        '你好，我是新建元的数字员工元元，请问有什么需要帮助的吗？',
        'stream_token',
        session.socket
      );
      client.setAISay('', 'stream_end', session.socket);
    }, 5000);
  }, [session]);

  function getCurrentDateTime() {
    const now = new Date();
    const year = now.getFullYear();
    const month = (now.getMonth() + 1).toString().padStart(2, '0');
    const day = now.getDate().toString().padStart(2, '0');
    const hours = now.getHours().toString().padStart(2, '0');
    const minutes = now.getMinutes().toString().padStart(2, '0');
    const seconds = now.getSeconds().toString().padStart(2, '0');
    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
  }
  // 更新时间用的变量
  let time = '';
  async function getResult(promtString: string, num: number) {
    let now_time = getCurrentDateTime();
    // 日志
    // session_rizhi.socket_rizhi.send(
    //   '数字人ID:' +
    //     urlParams.get('shuziren') +
    //     ' 发送问题给大模型时间：' +
    //     now_time +
    //     '，内容：' +
    //     promtString
    // ); // 发送一条日志消息
    // 发起请求之前，清空答案变量；生成一个消息
    dealResultStr = '';
    // 生成一个消息模板
    let messageId = uuidv4();
    currMessageId = messageId;
    let message1: IMessage = {
      id: messageId,
      author: '元元',
      authorIsUser: false,
      content: '',
      createdAt: new Date().toISOString()
    };
    time = ''; //这里需要清空
    // 获取答案：思考中
    setVoicing('event_vad_think');
    setTimeout(() => {
      // 上面的思考中是微观异步，使用宏观异步获取思考中的高度
      document.getElementsByClassName('overScroll')[0].style.height =
        document.getElementsByClassName('1111')[0].scrollHeight - 20 + 'px';
    }, 0);
    let streamController = await client.getLLMData(
      promtString,
      (done, token) => {
        // console.log('一次拉去数据==='+token)
        if (done) {
          client.setAISay('', 'stream_end', session.socket);
          // stream_start：开始推送数据
          // stream_token：正在推送数据
          // stream_end：推送数据正常结束
          // task_stop：用户打断当前交互流程
        } else {
          // session_rizhi.socket_rizhi.send('数字人ID:' + urlParams.get('shuziren') + ' 用于对比的currMessageId和messageId和num和initWAKEUP_NTF.num'
          //      + now_time + '，内容：' +'id_1'+currMessageId+'id_2'+messageId +'num'+num+'initWAKEUP_NTF.num'+initWAKEUP_NTF.num); // 发送一条日志消息

          // 这里很重要，如果已经有新的消息，之前被打断的消息就不要一直生成
          if (currMessageId != messageId) {
            // @ts-ignore
            streamController && streamController.close();
            return;
          } else if (currMessageId == messageId) {
            // 回调一次就要解析一次
            // 对比是不是同一个问题，保证下一个问题来时，上一个问题不会调用函数
            if (num == initWAKEUP_NTF.num) {
              dealResult(token, messageId, message1, num);
            } else {
              streamController && streamController.close();
            }
          }
        }
      }
    );
  }
//   // 假设这是中文标点符号的正则表达式
//   const punctuationRegex = /[。！？：，；（）【】《》“”‘’]/;
//
// // 用来保存前一次没有匹配到标点符号的剩余部分
//   let buffer = "";
//
// // 处理每次收到的数据
//   function processReceivedData(data) {
//     // 将当前数据与上次的暂存内容拼接
//     let combinedData = buffer + data;
//
//     // 查找第一个匹配的中文标点符号
//     const match = combinedData.match(punctuationRegex);
//
//     if (match) {
//       // 如果找到了匹配的标点符号
//       const matchIndex = combinedData.indexOf(match[0]);
//       // 将匹配到标点符号之前的部分作为一句话
//       const sentence = combinedData.slice(0, matchIndex + 1);
//
//       // 输出这一句话并保存剩余部分
//       console.log('匹配到的句子:', sentence);
//       buffer = combinedData.slice(matchIndex + 1); // 保存剩余部分
//     } else {
//       // 如果没有找到匹配的标点符号，暂存当前数据
//       buffer = combinedData;
//     }
//   }
  let storeTokens = '';
  // const punctuationRegex = /[，。、：；！？——（）“”]/;
  const punctuationRegex = /[ ，。；！]/;
  function processReceivedData(data: any) {
    // 将当前数据与上次的暂存内容拼接
    storeTokens += data;
    let match
    let result = []
    while((match = storeTokens.match(punctuationRegex)) !== null){
      try {
        // 如果找到了匹配的标点符号
        const matchIndex = storeTokens.indexOf(match[0]);
        // 将匹配到标点符号之前的部分作为一句话
        result.push(storeTokens.slice(0, matchIndex + 1))
        storeTokens = storeTokens.slice(matchIndex + 1); // 保存剩余部分
        punctuationRegex.lastIndex = 0;
      } catch (error) {
        continue
      }
    }
    result.length && result.map((item)=>{
      client.setAISay(item, 'stream_token', session.socket);
    })
  }
  const dealResult = (
    token: string,
    messageId: string,
    messageTemplate: IMessage,
    num: number
  ) => {
    let currResult = '';
    // 从字符串结果中获得对象
    let resultList = dealStr2Arr(token);

    // 得到正确的答案
    resultList.forEach((item) => {
      // console.log(item,'item');

      // if (item.path == '/streamed_output/-') {
      //   currResult += item.value;
      // }
      if (item.path == 'message') {
        currResult += item.value;
      }
    });

    dealResultStr += currResult;
    // 每次拉取的数据，有答案内容，就要播报和展示
    if (currResult) {
      // session_rizhi.socket_rizhi.send('大模型横屏 ResponseData-----------------' + currResult);
      // session_rizhi.socket_rizhi.send(
      //   '数字人ID:' +
      //     urlParams.get('shuziren') +
      //     'num和init_num数字对比：' +
      //     getCurrentDateTime() +
      //     '，内容：' +
      //     num +
      //     '和' +
      //     initWAKEUP_NTF.num
      // ); // 发送一条日志消息
      // console.log(currResult);
      processReceivedData(currResult);
      // 判断如果是新的答案还是旧的答案，如果是旧的答案减少接口调用
      if (num == initWAKEUP_NTF.num) {
        // client.setAISay(currResult, 'stream_token', session_rizhi.socket_rizhi);
        // 触发数字人讲话：开始讲话
        setVoicing('event_vad_begin');
      }
      let now_time = getCurrentDateTime();
      // 记录答案返回的时间展示
      if (!time) {
        time = new Date().toISOString();
        messageTemplate.createdAt = time;
      }
    //   console.log('对话返回时间：' + now_time + '，内容：' + dealResultStr);
    //   session_rizhi.socket_rizhi.send(
    //     '数字人ID:' +
    //       urlParams.get('shuziren') +
    //       ' 问题得到回答并展示时间：' +
    //       getCurrentDateTime() +
    //       '，内容：' +
    //       currResult
    //   ); // 发送一条日志消息
      setMessages((m) => {
        let oldLastMsg = m[m.length - 1];
        // 此消息已经存在，继续追加内容
        if (oldLastMsg.id == messageId) {
          // console.log('追加'+dealResultStr)
          return [
            ...m.slice(0, m.length - 1),
            { ...oldLastMsg, content: dealResultStr }
          ];
          // 需要新创建消息
        } else {
          // 如果最后一个消息不是当前正在回答的消息，
          // 而且当前消息用户的提问,这个时候才追加一个消息
          if (oldLastMsg.authorIsUser) {
            // console.log('新增'+dealResultStr)
            let tempMsg = { ...messageTemplate, content: dealResultStr };
            return [...m, tempMsg];
          } else {
            return [...m];
          }
        }
      });
    }
  };

  // 正则表达式匹配
// const regex = /data: (\{(?:[^{}]|(?:\{[^{}]*\}))*\})\n\n/g;
  const regex = /data: .*\n\n/g;
  let buffer = ''; // 初始化缓冲区
  const dealStr2Arr = (token: string) => {
    let match;
    const result = [];
    buffer += token
    // 循环匹配字符串中的所有对象并存入数组
    while ((match = regex.exec(buffer)) !== null) {
      try {
        const parsedData = JSON.parse(match[0].slice(5, -2));
        if(parsedData.event == "message" && parsedData.answer){
          result.push({ path: parsedData.event, value: parsedData.answer });
        }
        // 更新缓冲区：去掉已处理的部分
        buffer = buffer.slice(match.index + match[0].length);
        // 重置下次正则匹配的起始位置
        regex.lastIndex = 0;
      } catch (error) {
        // debugger;
        continue;
        console.error('解析 JSON 出错:', error);
      }
    }

    return result;
  };

  const adjustAspectRatio = () => {
    var aspectRatioBox = document.getElementById('digitalBoxId');
    var height = window.innerHeight;
    var width = height * (9 / 16);
    // @ts-ignore
    aspectRatioBox.style.width = width + 'px';
    setloadingFinish(true);
  };

  let currInput = '';

  useEffect(() => {
    // adjustAspectRatio();
    // 在窗口大小调整时重新计算宽度
    // window.addEventListener('resize', adjustAspectRatio);
  });

  function isFullScreen() {
    return !!(
      // @ts-ignore
      (
        document.fullscreen ||
        // @ts-ignore
        document.mozFullScreen ||
        // @ts-ignore
        document.webkitIsFullScreen ||
        // @ts-ignore
        document.webkitFullScreen ||
        // @ts-ignore
        document.msFullScreen
      )
    );
  }

  const [fullscreen, setfullscreen] = useRecoilState(fullscreenState);
  // 全屏
  const onFullScreen = () => {
    // 退出全屏
    if (isFullScreen()) {
      setfullscreen(false);
      // @ts-ignore
      if (document.exitFullscreen) {
        // @ts-ignore
        document.exitFullscreen();
        // @ts-ignore
      } else if (document.mozCancelFullScreen) {
        // Firefox
        // @ts-ignore
        document.mozCancelFullScreen();
        // @ts-ignore
      } else if (document.webkitExitFullscreen) {
        // Chrome, Safari and Opera
        // @ts-ignore
        document.webkitExitFullscreen();
        // @ts-ignore
      } else if (document.msExitFullscreen) {
        // Internet Explorer and Edge
        // @ts-ignore
        document.msExitFullscreen();
      }
      // 全屏
    } else {
      setfullscreen(true);
      // const element = document.getElementById('digitalBoxId');
      const element = document.getElementById('digitalBoxId') as HTMLElement;
      // @ts-ignore
      if (element.requestFullscreen) {
        // @ts-ignore
        element.requestFullscreen();
        // @ts-ignore
      } else if (element.mozRequestFullScreen) {
        // Firefox
        // @ts-ignore
        element.mozRequestFullScreen();
        // @ts-ignore
      } else if (element.webkitRequestFullscreen) {
        // Chrome, Safari and Opera
        // @ts-ignore
        element.webkitRequestFullscreen();
        // @ts-ignore
      } else if (element.msRequestFullscreen) {
        // Internet Explorer and Edge
        // @ts-ignore
        element.msRequestFullscreen();
      }
    }
  };

  return (
    <Box
        id="digitalBoxId"
      sx={{
        margin: '0',
        position: 'relative',
        width: '1920px',
        height: '1080px',
        overflow: 'hidden'
      }}
    >
      {/* <Box id='digitalBoxId' sx={{margin:'0 auto',position:'relative',width:'100vw',height:'100vh'}}> */}

      {/* <Box id='digitalBoxId' sx={{margin:'0 auto',position:'relative',height:'100vh',overflow:'hidden'}}> */}
      <Box
        sx={{
          width: '100%',
          height: '100%',
          overflow: 'hidden'
        }}
      >
        {/* <Human></Human> */}
        {/*<iframe style={{*/}
        {/*            width: '100%',*/}
        {/*            height: '100%',*/}
        {/*            border:'none'*/}
        {/*        }} src={shuziren} allowFullScreen></iframe>*/}
        {/* <img*/}
        {/*  src={BG}*/}
        {/*  style={{*/}
        {/*    width: '100%',*/}
        {/*    height: '100%',*/}
        {/*    border: 'none'*/}
        {/*  }}*/}
        {/*/>*/}
        <video
          autoPlay
          loop
          muted
          style={{
            height: '100%',
            border: 'none'
          }}>
          <source src={BG} type="video/mp4" />
        </video>
      </Box>
      <Box
        sx={{
          position: 'absolute',
          top: '0',
          bottom: '0',
          left: '0',
          right: '0',
          margin: 'auto',
          display: 'flex',
          alignItems: 'center',
          justifyContent: 'center',
          width: '75%',
          height: '75%',
          // width: '1449px',
          // height: '919px',
          zIndex: 99
        }}
      >
        <ChatBox></ChatBox>
        <Box
                  sx={{
            position: 'absolute',
            bottom: '-15px',
            right: '25px',
            cursor: 'pointer',
            zIndex: 99
          }}
        >
                  <img onClick={handleStopRendering} src={pauseIcon} style={{width:'115px',height:'30px'}}/>
        </Box>
      </Box>

      <Box
        position="absolute"
        right="40px"
        top="40px"
        color="#FFF"
        zIndex={99}
        onTouchStart={onFullScreen}
        onClick={onFullScreen}
      >
        <img src={fullscreenIcon} alt="widthFix"></img>
      </Box>
    </Box>
  );
}
